Лабораторная работа 12 "Увеличение количества источников прерываний с помощью схемы daisy chain"

В базовом варианте лабораторных работ предлагается реализовать процессорную систему с одним источником прерываний, чего достаточно для выполнения лабораторных работ. Однако, если появится желание усовершенствовать систему и увеличить количество периферийных устройств, то поддержка только одного источника прерываний создаст множество сложностей. В рамках данной лабораторной работы необходимо реализовать блок приоритетных прерываний и интегрировать его в контроллер прерываний, увеличив число потенциальных источников прерываний до 16.

Цель

  1. Разработать блок приоритетных прерываний (БПП), построенный по схеме daisy chain.
  2. Интегрировать БПП в контроллер прерываний.

Теория

Если процессорная система предполагает наличие более одного источника прерываний, то необходимо разобраться с тем, что делать в случае возникновения коллизий — наложения одновременных запросов прерываний от нескольких источников. Одним из способов решения такой проблемы является реализация приоритетов прерываний. Со схемотехнической точки зрения, проще всего реализовать схему со статическим, не изменяемым, приоритетом. Одной из таких схем является daisy chain (по-русски — гирлядна, или дейзи-чейн, или дейзи-цепочка). Пример такой схемы можно увидеть на рис. 1.

../../.pic/Labs/lab_12_daisy_chain/fig_01.png

Рисунок 1. Структурная схема daisy chain.

Данная схема состоит из двух массивов элементов И. Первый массив (верхний ряд элементов) формирует многоразрядный сигнал (назовем его для определенности ready, на рис. 1 он обозначен как "Приоритет"), который перемножается с запросами с помощью массива элементов И нижнего ряда, формируя многоразрядный сигнал y. Обратите внимание на то, что результат операции И на очередном элементе нижнего массива влияет на результат И следующего за ним элемента верхнего массива и наоборот (readyₙ₊₁ зависит от yₙ, в то время как yₙ зависит от readyₙ). Как только на одном из разрядов y появится значение 1, оно сразу же распространится в виде 0 по всем оставшимся последующим разрядам ready, обнуляя их. А обнулившись, разряды ready обнулят соответствующие разряды y (нулевые разряды ready запрещают генерацию прерывания для соответствующих разрядов y).

Нижний массив элементов И можно описать через непрерывное присваивание побитового И между ready и сигналом запросов на прерывание.

Для описания верхнего ряда элементов И вам будет необходимо сделать непрерывное присваивание readyₙ & !yₙ для n+1-ого бита ready. Для этого будет удобно воспользоваться конструкцией generate for, которая позволяет автоматизировать создание множества однотипных структур.

Рассмотрим принцип работы этой конструкции. Предположим, мы хотим создать побитовое присваивание 5-битного сигнала a 5-битному сигналу b.

Индексы, используемые конструкцией, должны быть объявлены с помощью ключевого слова genvar. Далее, в области, ограниченной ключевыми словами generate/endgenerate описывается цикл присваиваний / созданий модулей:

logic [4:0] a;
logic [4:0] b;

// ...

genvar i;
generate
  for(i = 0; i < 5; i++) begin
    assign a[i] = b[i];
  end
endgenerate

Разумеется в этом примере можно было бы просто сделать одно непрерывное присваивание assign a = b;, однако в случае реализации верхнего ряда элементов И, подобное многобитное непрерывное присваивание не приведет к синтезу требуемой схемы.

Практика

Рассмотрим реализацию нашего контроллера прерываний:

../../.pic/Labs/lab_12_daisy_chain/fig_02.drawio.svg

Рисунок 2. Структурная схема блока приоритетных прерываний.

Помимо портов clk_i и rst_i, модуль daisy_chain будет иметь 3 входа и три выхода:

  • masked_irq_i — 16-разрядный вход маскированного запроса на прерывания (т.е. источник прерывание уже прошел маскирование сигналом CS-регистра mie).
  • irq_ret_i — сигнал о возврате управления основному потоку инструкций (выход из обработчика прерываний).
  • ready_i — сигнал о готовности процессора к перехвату (т.е. прямо сейчас процессор не находится в обработчике перехвата). Это нулевой бит сигнала ready в дейзи-цепочке. Пока ready_i равен нулю, дейзи-цепочка не будет генерировать сигналы прерываний.
  • irq_o — сигнал о начале обработки прерываний.
  • irq_cause_o — причина прерывания.
  • irq_ret_o — сигнал о завершении обработки запроса на прерывания. Будет соответствовать cause_o в момент появления сигнала mret_i.

Внутренний сигнал cause является сигналом y с рис. 1. Как пояснялось выше, этот сигнал может содержать только одну единицу, она будет соответствовать прошедшему запросу на прерывание. А значит этот результат можно использовать в качестве сигнала для идентификации причины прерывания. При этом, свертка по ИЛИ этого сигнала даст итоговый запрос на прерывание.

Однако, как упоминалось в ЛР10, спецификация RISC-V накладывает определенные требования на кодирование кода mcause для причины прерывания. В частности, необходимо выставить старший бит в единицу, а значение на оставшихся битах должно быть больше 16. Схемотехнически это проще реализовать выполнив склейку {12'h800, cause, 4'b0000} — в этом случае старший разряд будет равен единице, и если хоть один разряд cause будет равен единице (а именно это и является критерием появления прерывания), младшие 31 бит mcause будут больше 16.

Регистр на рис. 2 хранит значение внутреннего сигнала cause, чтобы по завершению прерывания выставить единицу на соответствующем разряде сигнала irq_ret_o, который сообщит устройству, чье прерывание обрабатывалось ранее, что его обработка завершена.

Задание

  • Реализовать модуль daisy_chain.
  • Интегрировать daisy_chain в модуль irq_controller по схеме, представленной на рис. 3.
  • Отразить изменения в прототипе сигнала irq_controller в модулях riscv_core и riscv_unit.

../../.pic/Labs/lab_12_daisy_chain/fig_03.drawio.svg

Рисунок 3. Структурная схема блока приоритетных прерываний.

Обратите внимание, что разрядность сигналов irq_req_i, mie_i, irq_ret_o изменилась. Теперь это 16-разрядные сигналы. Сигнал, который ранее шел на выход к irq_ret_o теперь идет на вход irq_ret_i модуля daisy_chain. Формирование кода причины прерывания irq_cause_o перенесено в модуль daisy_chain.

Порядок выполнения работы

  1. Опишите модуль daisy_chain.
    1. При формировании верхнего массива элементов И с рис. 2, вам необходимо воспользоваться сформировать 16 непрерывных присваиваний через блок generate for.
    2. Формирование нижнего массива элементов И можно сделать с помощью одного непрерывного присваивания посредством операции побитовое И.
    3. Проверьте модуль daisy_chain с помощью модуля tb_daisy_chain.
  2. Интегрируйте модуль daisy_chain в модуль irq_controller по схеме, представленной на рис. 3.
    1. Не забудьте обновить разрядность сигналов irq_req_i, mie_i, irq_ret_o.
    2. Также не забудьте обновить разрядность сигналов irq_req_i, irq_ret_o в riscv_core и riscv_unit, также использовать младшие 16 бит сигнала mie вместо одного при подключении модуля irq_controller.